/*
 * Copyright 2011 The Rusted Roof, LLC.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package org.proteusframework.api.model;

import org.proteusframework.util.Assert;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.logging.Logger;

/**
 * Fully qualified name that includes two additional properties, name and description. Displayable names are used to in
 * a UI to present the user with more meaningful names.
 *
 * @author Tacoma Four
 */
public final class DisplayableName extends QualifiedName implements IDisplayableName
{
    private static final Logger logger = Logger.getLogger(DisplayableName.class.getCanonicalName());

    private static final String MISSING_ICON = "/org/proteusframework/resources/missing.png";

    private String name;
    private String description;
    private BufferedImage icon;

    /**
     * Defines an immuntable displayable name with a default icon.
     *
     * @param namespace   Namespace, typically reverse domain notation
     * @param id          Unique ID within the given namespace
     * @param name        Human readable name
     * @param description Human readable description. If a null is passed, it is converted to an empty-string.
     * @throws IllegalArgumentException when namespace, id, or name is null
     */
    public DisplayableName(String namespace, String id, String name, String description)
    {
        this(namespace, id, name, description, (String) null);
    }

    /**
     * Defines an immuntable displayable name with a default icon.
     *
     * @param namespace   Namespace, typically reverse domain notation
     * @param id          Unique ID within the given namespace
     * @param name        Human readable name
     * @param description Human readable description. If a null is passed, it is converted to an empty-string.
     * @param iconPath    Fully qualified path to the image to use when graphically representing this object
     * @throws IllegalArgumentException when namespace, id, or name is null
     */
    public DisplayableName(String namespace, String id, String name, String description, String iconPath)
    {
        super(namespace, id);
        Assert.parameterNotNull(name, "Parameter 'name' must not be null");

        this.name = name;
        this.description = (null == description) ? "" : description;

        if (null == iconPath)
        {
            assignMissingIcon();
        } else
        {
            URL url = this.getClass().getResource(iconPath);
            try
            {
                this.icon = ImageIO.read(url);
            } catch (IOException e)
            {
                logger.warning("Unable to locate " + iconPath + e.getMessage());
                assignMissingIcon();
            }
        }
    }

    /**
     * Defines an immutable displayable name with a default icon.
     *
     * @param namespace   Namespace, typically reverse domain notation
     * @param id          Unique ID within the given namespace
     * @param name        Human readable name
     * @param description Human readable description. If a null is passed, it is converted to an empty-string.
     * @param icon        Image to use when graphically representing this object
     * @throws IllegalArgumentException when namespace, id, or name is null
     */
    public DisplayableName(String namespace, String id, String name, String description, BufferedImage icon)
    {
        super(namespace, id);
        Assert.parameterNotNull(name, "Parameter 'name' must not be null");

        this.name = name;
        this.description = (null == description) ? "" : description;

        if (null == icon)
        {
            assignMissingIcon();
        } else
        {
            this.icon = icon;
        }
    }

    private void assignMissingIcon()
    {
        URL missingUrl = this.getClass().getResource(MISSING_ICON);
        try
        {
            this.icon = ImageIO.read(missingUrl);
        } catch (IOException e)
        {
            logger.warning("Unable to locate " + MISSING_ICON + ": " + e.getMessage());
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getDescription()
    {
        return description;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public BufferedImage getIcon()
    {
        return icon;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getName()
    {
        return name;
    }

    @Override
    public String toString()
    {
        return "DisplayableName{" +
                "namespace='" + namespace + '\'' +
                ", id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", description='" + description + '\'' +
                '}';
    }
}
